Переменные и типы данных в PHP
Переменные и типы данных
Переменные
В PHP переменная — это именованный контейнер для временного хранения значения в памяти. Все переменные в PHP начинаются со знака доллара ($), за которым следует идентификатор.
$<имя> = <значение>;
Идентификатор должен соответствовать следующим правилам:
- первый символ после
$— буква латинского алфавита (a–z,A–Z) или символ подчёркивания (_); - последующие символы могут включать буквы, цифры (
0–9) и подчёркивания; - регистр имеет значение:
$name,$Nameи$NAME— три разные переменные.
Примеры корректных имён:
$userName
$_cacheKey
$totalAmount2024
Примеры некорректных имён:
$1user // начинается с цифры — синтаксическая ошибка
$user-name // дефис недопустим — интерпретируется как вычитание
$user name // пробел недопустим — синтаксическая ошибка
В отличие от некоторых других языков (например, C# или Java), в PHP отсутствует обязательное объявление переменной перед использованием. Переменная считается созданной в момент первого присваивания значения. Если переменная используется до присваивания, PHP генерирует предупреждение уровня E_NOTICE, а само выражение ведёт себя так, будто переменная содержит значение null. Это поведение, с одной стороны, упрощает написание небольших сценариев, с другой — повышает риск опечаток и трудноуловимых логических ошибок. Поэтому настоятельно рекомендуется включать режим отладки с полным набором отчётов об ошибках (error_reporting = E_ALL) на всех этапах разработки, включая тестирование.
Область видимости переменных в PHP определяется контекстом: глобальная, локальная (внутри функции), статическая (сохраняющая значение между вызовами функции), или суперглобальная (предопределённые массивы, такие как $_GET, $_POST, $_SERVER). Переменные, объявленные вне функций и классов, существуют в глобальной области видимости. Внутри функций по умолчанию доступны только локальные переменные; для доступа к глобальной переменной необходимо явно использовать ключевое слово global или обращаться через суперглобальный массив $GLOBALS. Такое поведение способствует инкапсуляции, но требует осознанного управления состоянием.
В PHP переменные реализованы как zval (Zend value) — внутренняя структура данных Zend Engine, содержащая само значение, его тип, счётчик ссылок и флаги. Это позволяет эффективно реализовать семантику копирования при записи (copy-on-write): при присваивании одной переменной другой на уровне PHP создаётся новая ссылка на тот же zval; копирование происходит только в момент модификации. Таким образом, PHP балансирует между удобством высокоуровневых операций и производительностью низкоуровневого выполнения.
Переменная используется по имени для получения её текущего значения. Для использования переменной тоже требуется использовать символ $:
$<имя>
Пример:
echo "User: " . $username;
$total = $price * $quantity;
Допустимо присваивание по ссылке. Создаётся новая переменная, ссылающаяся на то же значение в памяти. Изменения в одной отражаются в другой.
$<новая_переменная> = &$<существующая_переменная>;
Пример:
$a = 10;
$b = &$a;
$b = 20;
echo $a; // Выведет 20
Проверка существования переменной возвращает true, если переменная объявлена и не равна null.
Шаблон:
isset($<имя>)
Пример:
if (isset($email)) {
sendNotification($email);
}
Удаление переменной освобождает память, занимаемую переменной, и делает её неопределённой.
Шаблон:
unset($<имя>);
Пример:
unset($tempData);
// echo $tempData; // вызовет E_NOTICE
Система типов в PHP
PHP поддерживает восемь типов данных, которые условно делятся на три категории:
Скалярные типы (scalar types)
К ним относятся значения, представляющие единичные, неделимые сущности:
boolean
boolean — логический тип, принимающий ровно два значения: true и false. В контекстах, ожидающих булево значение (например, в условных операторах if, while), PHP применяет правила приведения к булеву типу (boolean conversion). Следующие значения считаются ложными (false):
false, 0 (целое), 0.0 (вещественное), пустая строка "" или строка "0", пустой массив [], null, а также объекты некоторых расширений (например, SimpleXML с пустым документом).
Все остальные значения интерпретируются как true.
$isReady = true;
$hasError = false;
if ($isReady) {
echo "Готово к работе";
}
// Приведение к boolean
var_dump((bool) ""); // false
var_dump((bool) "0"); // false
var_dump((bool) "hello"); // true
Шаблоны:
- Объявление:
$<имя> = true;или$<имя> = false; - Проверка:
if ($<имя>) { ... } - Приведение:
(bool)$<значение>
integer
integer — целое число со знаком. Диапазон зависит от разрядности системы: на 32-битных платформах — от −2 147 483 648 до 2 147 483 647; на 64-битных — от −9 223 372 036 854 775 808 до 9 223 372 036 854 775 807. PHP поддерживает запись целых чисел в десятичной, шестнадцатеричной (0x...), восьмеричной (0...) и двоичной (0b...) системах счисления. Переполнение целого числа автоматически преобразует его в тип float, что может привести к потере точности.
$count = 42;
$hex = 0xFF; // 255
$bin = 0b1010; // 10
$oct = 0755; // 493
echo $count + 10; // 52
// Переполнение → float
$big = 9223372036854775807;
$big++; // теперь $big — float
var_dump($big); // float(9.2233720368548E+18)
Шаблоны:
- Объявление:
$<имя> = <целое_число>; - Системы счисления:
- Десятичная:
123 - Шестнадцатеричная:
0xABC - Восьмеричная:
0755 - Двоичная:
0b1101
- Десятичная:
- Приведение:
(int)$<значение>
float
float (также известен как double или real) — число с плавающей запятой. Реализован в соответствии со стандартом IEEE 754 двойной точности (64 бита). Следует помнить, что числа с плавающей запятой не могут точно представлять все десятичные дроби (например, 0.1 + 0.2 !== 0.3), что является фундаментальным ограничением двоичной арифметики. Для финансовых расчётов рекомендуется использовать расширение bcmath или хранить денежные суммы в минимальных единицах (например, копейках) как целые числа.
$price = 19.99;
$scientific = 1.23e4; // 12300.0
// Осторожно: неточность
$a = 0.1;
$b = 0.2;
echo ($a + $b == 0.3) ? 'равно' : 'не равно'; // не равно
// Использование bcmath для точных вычислений
echo bcadd('0.1', '0.2', 1); // "0.3"
Шаблоны:
- Объявление:
$<имя> = <дробное_число>; - Научная нотация:
1.23e-4 - Приведение:
(float)$<значение>или(double)$<значение>
string
string — последовательность байтов, интерпретируемых как текст. Строка может быть в UTF-8, Windows-1251, KOI8-R и т.д. Важно, что встроенные строковые функции (например, strlen(), substr()) работают с байтами, а не с символами Unicode. Для корректной работы с многобайтовыми кодировками (в первую очередь UTF-8) следует использовать функции из расширения mbstring (mb_strlen(), mb_substr() и др.). Строки могут быть объявлены в одинарных ('...'), двойных ("...") кавычках или с использованием синтаксиса heredoc/nowdoc. В двойных кавычках и heredoc поддерживаются интерполяция переменных и escape-последовательности (например, "\n"), в одинарных — только escape-последовательности \' и \\.
$name = 'Alice';
$message = "Hello, $name!";
$heredoc = <<<EOT
Привет, $name!
Это многострочный текст.
EOT;
$nowdoc = <<<'EOT'
Переменные $name не интерполируются.
EOT;
echo strlen($name); // 5 (байты!)
echo mb_strlen($name, 'UTF-8'); // 5 (символы)
// Конкатенация
$full = $name . " Smith";
// Интерполяция
echo "User: $name"; // работает только в двойных кавычках
Шаблоны:
- Одинарные кавычки:
$<имя> = 'текст';— без интерполяции - Двойные кавычки:
$<имя> = "текст с $переменной"; - Heredoc:
$<имя> = <<<МЕТКА
текст с $переменной
МЕТКА; - Nowdoc:
$<имя> = <<<'МЕТКА'
текст без интерполяции
МЕТКА; - Работа с Unicode:
mb_*()функции вместоstrlen(),substr()и т.д.
Составные типы (compound types)
array
array — упорядоченная коллекция пар ключ–значение. Ключом может быть целое число (integer) или строка (string); значением — любой тип, включая другой массив (вложенность не ограничена). Массивы в PHP объединяют функциональность списков, словарей, хэш-таблиц и множеств. Существует два основных вида: индексированные (ключи — последовательные целые числа, начиная с 0) и ассоциативные (ключи — произвольные строки или числа). С версии PHP 7.4 появилась поддержка типизированных массивов в объявлениях свойств классов (array<string, int>), а с PHP 8.0 — union-типов и mixed, что улучшает статическую проверку.
- Индексированный:
$<имя> = [<элемент1>, <элемент2>, ...]; - Ассоциативный:
$<имя> = ["<ключ1>" => <значение1>, "<ключ2>" => <значение2>];
Массив — универсальная структура для хранения коллекций данных.
Примеры:
$colors = ["red", "green", "blue"];
$user = [
"name" => "Bob",
"age" => 35,
"active" => true
];
Доступ к элементу массива позволяет получить значение по ключу (строковому или числовому).
Шаблон:
$<массив>[<ключ>]
Пример:
echo $user["name"]; // "Bob"
echo $colors[0]; // "red"
// Индексированный
$colors = ['red', 'green', 'blue'];
// Ассоциативный
$user = [
'name' => 'Bob',
'age' => 30,
'active' => true
];
// Вложенный
$config = [
'db' => ['host' => 'localhost', 'port' => 5432],
'cache' => ['ttl' => 3600]
];
// Добавление
$colors[] = 'yellow'; // в конец
$user['email'] = 'bob@example.com';
// Чтение
echo $user['name']; // Bob
// Итерация
foreach ($user as $key => $value) {
echo "$key: $value\n";
}
// Проверка существования ключа
if (isset($user['email'])) { /* ... */ }
Шаблоны:
- Объявление:
$<имя> = [<элементы>]; - Индексированный:
$<имя> = [знач1, знач2]; - Ассоциативный:
$<имя> = ["ключ" => значение]; - Доступ:
$<массив>[<ключ>] - Добавление:
$<массив>[] = значение;или$<массив>["новый_ключ"] = значение; - Типизация (PHP 7.4+):
private array<string, int> $map;
object
object — экземпляр класса. Объекты передаются по ссылке (начиная с PHP 5; в PHP 4 передавались по значению). Объект может содержать свойства и методы, наследоваться от других классов, реализовывать интерфейсы. Даже если все свойства объекта удалены или имеют значение null, сам объект не равен null: new stdClass() !== null.
Создание объекта:
$<имя> = new <Класс>(<аргументы>);
Пример:
$logger = new Monolog\Logger('app');
$point = new Point(10, 20);
Доступ к свойству объекта:
$<объект>-><свойство>
Пример:
echo $point->x;
$point->y = 30;
Вызов метода объекта:
$<объект>-><метод>(<аргументы>);
Пример:
$logger->info("User logged in");
$distance = $point->distanceTo($origin);
Проверка принадлежности объекта к классу:
$<объект> instanceof <Класс>
Пример:
if ($handler instanceof RequestHandlerInterface) {
$response = $handler->handle($request);
}
class Point {
public float $x;
public float $y;
public function __construct(float $x, float $y) {
$this->x = $x;
$this->y = $y;
}
public function distanceToOrigin(): float {
return sqrt($this->x ** 2 + $this->y ** 2);
}
}
$p = new Point(3.0, 4.0);
echo $p->x; // 3
echo $p->distanceToOrigin(); // 5
// Объект ≠ null
var_dump($p === null); // false
// Клонирование (если нужно копирование)
$q = clone $p;
Специальные типы
null
null — единственный возможный тип значения null. Обозначает отсутствие значения. Переменная имеет тип null, если:
— ей явно присвоено null;
— она объявлена, но ей ещё не присвоено никакое значение;
— она была уничтожена с помощью unset().
PHP не различает необъявленную и объявленную, но имеющую значение null переменную при чтении — в обоих случаях возникает E_NOTICE, а результат выражения — null. Однако функция isset() вернёт false и в первом, и во втором случае, тогда как array_key_exists() или оператор ?? (null coalescing) позволяют различать «отсутствие» и «явное null» в массивах и свойствах объектов.
$value = null;
unset($temp); // $temp теперь null при чтении (с E_NOTICE)
// Безопасное извлечение
$username = $_GET['user'] ?? 'guest';
// Проверка
if ($value === null) {
echo "Значение отсутствует";
}
// isset vs null coalescing
var_dump(isset($undefined)); // false
var_dump($undefined ?? 'default'); // "default"
Шаблоны:
- Присваивание:
$<имя> = null; - Проверка:
if ($<имя> === null) { ... } - Безопасное чтение:
$<результат> = $<возможно_null> ?? <по_умолчанию>; - Удаление:
unset($<имя>);
resource
resource (устаревший) — специальный тип, представляющий ссылку на внешний ресурс: дескриптор файла, соединение с БД, изображение GD и т.п. Начиная с PHP 8.0 многие ресурсы были заменены на объекты (например, mysqli вместо ресурса mysql), и тип resource постепенно выводится из употребления. Тем не менее, в унаследованном коде он встречается часто. Ресурсы автоматически освобождаются при уничтожении переменной, но рекомендуется закрывать их явно (например, fclose(), mysqli_close()), особенно в долгоживущих скриптах.
Дополнительно, начиная с PHP 8.0, введён псевдотип mixed, обозначающий «любой тип», и с PHP 8.1 — never (для функций, которые никогда не возвращают управление). Эти типы используются в строгих объявлениях типов и аналитических инструментах, но не влияют на runtime-поведение.
$file = fopen('data.txt', 'r');
$connection = mysqli_connect('localhost', 'user', 'pass', 'db');
$image = imagecreatefrompng('image.png');
// Чтение файла
if ($file) {
$content = fread($file, filesize('data.txt'));
fclose($file); // рекомендуется явно закрывать
}
// Работа с БД (устаревший стиль)
if ($result = mysqli_query($connection, "SELECT 1")) {
mysqli_free_result($result);
}
mysqli_close($connection);
Шаблоны:
- Получение ресурса:
$<имя> = <функция_возврата_ресурса>(...); - Закрытие:
<функция_закрытия>($<ресурс>);(например,fclose,mysqli_close) - Проверка:
if ($<ресурс>) { ... } - Типизация: не поддерживается напрямую; заменён объектами в современных расширениях
Дополнительные псевдотипы (PHP 8.0+)
mixed
Примеры кода
function logValue(mixed $value): void {
if (is_string($value)) {
echo "Строка: $value";
} elseif (is_array($value)) {
print_r($value);
}
}
Шаблоны
- Используется только в объявлениях типов:
function f(mixed $x): mixed - Не может быть использован в runtime-выражениях
- Эквивалентен union-типу
object|resource|array|string|int|float|bool|null
never
Примеры кода
function abort(string $message): never {
throw new RuntimeException($message);
}
function loopForever(): never {
while (true) {
// бесконечный цикл
}
}
Шаблоны
- Только как возвращаемый тип:
function <имя>(...): never - Указывает, что функция никогда не завершается нормально (либо выбрасывает исключение, либо зацикливается)
Преобразование типов
Одна из самых дискуссионных особенностей PHP — его активное использование неявного (автоматического) приведения типов. Интерпретатор стремится избежать фатальных ошибок при выполнении операций с несовместимыми типами, поэтому вместо прерывания выполнения он пытается преобразовать операнды к «подходящему» типу в соответствии с внутренними правилами. Эти правила последовательно закреплены в документации и реализованы в Zend Engine; однако их сложность и контекстная зависимость часто становятся источником неожиданного поведения.
Контексты, вызывающие неявное приведение
Неявное преобразование происходит в следующих ситуациях:
-
Арифметические операции (
+,-,*,/,%,**).
Все операнды приводятся к числу — либоinteger, либоfloat, в зависимости от содержимого. Если строка начинается с цифр (возможно, с ведущих пробелов), она интерпретируется как число до первого недопустимого символа:"123abc"→123,"12.3e2xyz"→1230.0. Строка, не начинающаяся с цифры (например,"abc123"), превращается в0. Пустая строка""и строка"0"также дают0, но с разными флагами внутреннего представления — это может повлиять на последующее сравнение. -
Логические операции и условия (
&&,||,!,if,while,?:).
Все значения приводятся кbooleanпо правилам, описанным ранее. Особенно важно помнить, что строка"0"— единственная непустая строка, которая считается ложной. -
Строковый контекст (конкатенация
.,echo,print, интерполяция в двойных кавычках).
Значения приводятся к строке. Дляnullрезультат — пустая строка""; дляboolean—"1"(true) или""(false); дляinteger/float— десятичное представление; дляarrayилиobjectбез метода__toString()— ошибка уровняE_RECOVERABLE_ERROR(начиная с PHP 8.0 —TypeError). -
Сравнение с оператором равенства (
==).
PHP приводит оба операнда к общему типу, руководствуясь таблицей loose comparison. Например,"0" == false→true,0 == "abc"→true,"123" == 123→true, но"123a" == 123→true, а"a123" == 123→false. Такое поведение делает==крайне ненадёжным для валидации входных данных.
Явное приведение (кастинг)
Разработчик может управлять преобразованием типов вручную, используя один из трёх механизмов:
-
Оператор кастинга в скобках (
(type)).
Это наиболее распространённый и производительный способ. Поддерживаемые формы:(int),(integer)(bool),(boolean)(float),(double),(real)(string)(array)(object)(unset)— эквивалентен присваиваниюnull(устаревшее, не рекомендуется)
Примеры:
$str = " 42 apples";
$num = (int)$str; // 42 — отбрасывается всё после цифр
$bool = (bool)"0"; // false — строка "0" → false
$arr = (array)$num; // [0 => 42]
$obj = (object)['x' => 1]; // объект stdClass со свойством x = 1Кастинг — это выражение. Он создаёт новое значение заданного типа.
Шаблоны:
(int)$<значение>(float)$<значение>(string)$<значение>(bool)$<значение>(array)$<значение>(object)$<значение>
-
Функция
settype($var, $type).
Изменяет непосредственно переменную, переданную по ссылке. Возвращаетtrueпри успехе,false— при недопустимом типе. Поддерживает те же строковые имена типов, что и оператор кастинга:'integer','double','string','array','object','boolean','null'.$value = "123";
settype($value, 'integer'); // $value теперь 123 (int)Преимущество
settype()— возможность динамического указания целевого типа (например, из конфигурации). Недостаток — побочный эффект изменения переменной и чуть более высокие накладные расходы. -
Специализированные функции преобразования.
Некоторые преобразования требуют дополнительной логики и реализованы в виде отдельных функций:intval(),floatval(),strval()— аналоги(int),(float),(string), но принимают второй параметр (основание системы счисления дляintval()).boolval()(PHP 5.5+) — явное приведение кboolean.json_encode()/json_decode()— сериализация/десериализация с контролем типов.filter_var()— валидация и санитизация с приведением (например,FILTER_VALIDATE_INT).
Таблица приоритетов при неявном приведении
При операциях с разнотипными операндами PHP выбирает целевой тип по следующим приоритетам (от высшего к низшему):
| Контекст | Целевой тип | Пояснение |
|---|---|---|
| Арифметика | float → integer | float имеет приоритет над integer. Если хотя бы один операнд float → результат float. |
Сравнение (==) | Зависит от пары типов | Используется внутренняя таблица loose comparison (см. ниже). |
| Логический контекст | boolean | Всё приводится к true/false. |
| Строковый контекст | string | Вызывается внутренний механизм преобразования в строку (например, zend_string_from_long). |
Для сравнения через == действует следующее упрощённое правило (полная таблица — в официальной документации PHP):
- Если один из операндов —
boolean, оба приводятся кboolean. - Иначе, если один из операндов —
object, применяется специальная логика (часто — попытка cast кstringилиint). - Иначе, если оба операнда — строки, сравниваются как строки (лексикографически, побайтово).
- Иначе — оба приводятся к
floatи сравниваются численно.
Отсюда, например, следует:
0 == "0e12345"→true(оба становятсяfloat:0.0 == 0.0);"1" == "01"→false(сравнение как строк:"1"≠"01");true == "php"→true("php"→true,true == true).
Проверка типов
PHP предоставляет два семейства функций для работы с типами: определение текущего типа и проверка на соответствие типу.
gettype($var)
Функция возвращает строку с именем типа переменной:
"boolean", "integer", "double" (обратите внимание: не "float"), "string", "array", "object", "resource", "NULL".
Это — диагностический инструмент, полезный при отладке. Однако не следует использовать gettype() в условиях ветвления, поскольку:
- строковое сравнение медленнее прямой проверки;
- имена типов (например,
"double") могут ввести в заблуждение; - логика, зависящая от конкретного типа, часто нарушает принципы полиморфизма.
Пример (не рекомендуется в production-коде):
if (gettype($input) === 'string') {
// обработка строки
}
Семейство функций is_*()
Это — основной механизм проверки типов в runtime. Все функции возвращают true или false. Наиболее важные:
| Функция | Проверяет | Особенности |
|---|---|---|
is_bool($v) | boolean | — |
is_int($v), is_integer($v), is_long($v) | integer | Три синонима. |
is_float($v), is_double($v), is_real($v) | float | Три синонима. |
is_string($v) | string | — |
is_array($v) | array | — |
is_object($v) | object | — |
is_null($v) | null | Эквивалент ($v === null) |
is_resource($v) | resource | Устаревает, но актуален для legacy-кода |
is_numeric($v) | число или строка, содержащая число | Возвращает true для "123", "12.3", "1e5", но false для "123abc" |
is_scalar($v) | скалярный тип (bool, int, float, string) | — |
is_callable($v) | может ли значение быть вызвано как функция | Проверяет Closure, имя функции, [$obj, 'method'] и др. |
Обратите внимание на различие между is_numeric() и (float)-кастингом:
is_numeric("123abc") → false, а (float)"123abc" → 123.0.
Шаблоны:
is_int($<значение>)is_float($<значение>)is_string($<значение>)is_bool($<значение>)is_array($<значение>)is_object($<значение>)is_null($<значение>)
Примеры:
if (is_string($input)) {
$length = strlen($input);
}
if (is_array($data)) {
foreach ($data as $item) { /* ... */ }
}
Оператор instanceof
Для объектов ключевой инструмент — оператор instanceof. Он проверяет, является ли объект экземпляром заданного класса, его наследником или реализует указанный интерфейс.
if ($logger instanceof Psr\Log\LoggerInterface) {
$logger->info('Event occurred');
}
Это предпочтительный способ проверки типов объектов — он устойчив к рефакторингу и поддерживает полиморфизм.
Сравнение: == и ===
PHP поддерживает два оператора равенства:
==(loose equality) — сравнивает значения после неявного приведения типов.===(strict equality) — сравнивает и значение, и тип; возвращаетtrueтолько если оба операнда идентичны по значению и типу.
Примеры:
"0" == 0; // true — loose: string → int
"0" === 0; // false — strict: string ≠ integer
null == false; // true — loose: null → false
null === false; // false — strict: null ≠ boolean
"123" == 123; // true
"123" === 123; // false
true == "1"; // true
true === "1"; // false
Рекомендация: всегда используйте === и !==, за исключением случаев, когда loose-сравнение намеренно и осознанно применяется (например, при обработке пользовательского ввода, где "0" и 0 семантически равнозначны). Особенно критично это при:
- валидации форм;
- работе с возвращаемыми значениями функций (некоторые функции возвращают
falseпри ошибке и0как корректный результат); - сравнении с
null(используйте=== null, а не== null).
Начиная с PHP 8.0, введён оператор nullsafe (?->), а с PHP 7.0 — оператор null coalescing (??), которые позволяют избежать явных проверок === null в цепочках вызовов и извлечении значений:
$username = $_GET['user'] ?? 'guest';
$length = $user?->getName()?->length ?? 0;
Шаблон сравнения с учетом типа:
$<значение1> === $<значение2>
Пример:
if ($status === "active") {
grantAccess();
}
if ($count === 0) {
showEmptyMessage();
}